package ude.univ.esiag.gon.uchiha.topic;

import java.util.StringTokenizer;
import java.util.Vector;


import ude.univ.esiag.gon.uchiha.data.DataObject;
import ude.univ.esiag.gon.uchiha.listener.TopicListener;
import ude.univ.esiag.gon.uchiha.operation.Operation;
import ude.univ.esiag.gon.uchiha.reader.DataReader;
import ude.univ.esiag.gon.uchiha.register.Multicaster;
import ude.univ.esiag.gon.uchiha.subscriber.impl.SubscriberImpl;
import ude.univ.esiag.gon.uchiha.writer.DataWriter;


public class Topic {
	private Vector<Topic> topics;
	private String simpleName;
	private String name;
	private DataObject data;
	private SubscriberImpl subscriber = null;// seted on DataReader
	private String subscriberIOR;
	private DataWriter writer;
	private Vector<TopicListener> listeners;
	public Topic(String simpleName, String name) {
		listeners = new Vector<TopicListener>();
		writer = new DataWriter();
		topics = new Vector<Topic>();
		this.simpleName = simpleName;
		this.name = name;
		data = new DataObject(null);
		data.setTopicName(name);
		new DataReader(this);
		if(simpleName.equals(name)){
			Multicaster.getInstance().registerRoot(this);
		}
	}
	public void modifieCache(Object obj){
		data.setObj(obj);
		for(int i = 0;i<listeners.size();i++){
			listeners.get(i).modifiedCache(data);
		}
	}
	public void addTopicListener(TopicListener listener){
		listeners.add(listener);
	}
	public void setSubscriberIOR(String subscriberIOR) {
		this.subscriberIOR = subscriberIOR;
	}
	public String getSubscriberIOR() {
		return subscriberIOR;
	}
	public DataWriter getWriter() {
		return writer;
	}
	public void createTopicFromSerializableTopic(SerializableTopic topic){
		data.setObj(topic.getData().getObj());
		for(int i = 0;i<topic.size();i++){
			SerializableTopic topic1 = topic.get(i);
			Topic topic2 = new Topic(topic1.getSimpleName(), topic1.getName());
			for(int j = 0;j<listeners.size();j++){
				topic2.addTopicListener(listeners.get(j));
			}
			topic2.getData().setObj(topic1.getData().getObj());
			topics.add(topic2);
			for(int j = 0;j<listeners.size();j++){
				listeners.get(j).modifiedTopic(this);
			}
			resumeTopicCreation(topic2);
			topic2.createTopicFromSerializableTopic(topic1);
		}
	}
	public DataObject getData() {
		return data;
	}
	public void resumeTopicCreation(Topic topic){
		int index = name.indexOf(".");
		Topic topicRoot = this;
		if(index != -1){
			String rootName = name.substring(0, index);
			topicRoot = Multicaster.getInstance().getTopicByName(rootName);
		}
		String ior1 = topic.getSubscriberIOR();
		if(ior1 == null){
			SubscriberImpl subscriber1 = topic.getSubscriber();
			ior1 = Multicaster.getInstance().subscriber_to_ior(subscriber1);
			topic.setSubscriberIOR(ior1);
		}
		Operation operation = new Operation(topic.getName(), ior1);
		operation.setTarget(Operation.TOPIC);
		operation.setType(Operation.GETIOR);
		operation.setToReplicate(false);
		topicRoot.getWriter().write(operation);
	}
	public SerializableTopic createTopicS(){
		SerializableTopic topic = new SerializableTopic(simpleName, name, data);
		for(int i = 0;i<topics.size();i++){
			SerializableTopic topic1 = topics.get(i).createTopicS();
			topic.addTopic(topic1);
		}
		return topic;
	}
	public void setSubscriber(SubscriberImpl subscriber) {
		this.subscriber = subscriber;
	}
	public SubscriberImpl getSubscriber() {
		return subscriber;
	}
	private Topic existeSame(String simpleName){
		for(int i = 0;i<topics.size();i++){
			if(topics.get(i).getSimpleName().equals(simpleName))
				return topics.get(i);
		}
		return null;
	}
	public Topic addTopic(String simpleName){
		Topic topic = existeSame(simpleName);
		if(topic != null)
			return topic;
		topic = new Topic(simpleName, name + "." + simpleName);
		for(int j = 0;j<listeners.size();j++){
			topic.addTopicListener(listeners.get(j));
		}
		topics.add(topic);
		for(int j = 0;j<listeners.size();j++){
			listeners.get(j).modifiedTopic(this);
		}
		return topic;
	}
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		for(int i = 0;i<getLevel();i++){
			sb.append("-");
		}
		if(data.getObj() != null){
			sb.append(simpleName + "[" + data.getObj().getClass().getSimpleName() + "]\n");
		}else{
			sb.append(simpleName + "[null]\n");
		}
		for(int i = 0;i<topics.size();i++){
			sb.append(topics.get(i).toString());
		}
		return sb.toString();
	}
	public Topic getTopic(String name){
		StringTokenizer tokens = new StringTokenizer(name, ".");
		String token = tokens.nextToken();
		if(token == null)
			return null;
		if(!tokens.hasMoreTokens())
			return this;
		if(token.equals(simpleName)){
			String token1 = tokens.nextToken();
			for(int i = 0;i<topics.size();i++){
				if(topics.get(i).getSimpleName().equals(token1)){
					StringBuilder sb = new StringBuilder(token1);
					while(tokens.hasMoreTokens()){
						sb.append("." + tokens.nextToken());
					}
					return topics.get(i).getTopic(sb.toString());
				}
			}
		}
		return null;
	}
	public int getLevel(){
		StringTokenizer tockens = new StringTokenizer(name, ".");
		return tockens.countTokens();
	}
	public String getName() {
		return name;
	}
	public String getSimpleName(){
		return simpleName;
	}
}
